// Copyright (C) 2023 即时通讯网(52im.net) & Jack Jiang.
// The RainbowChat Project. All rights reserved.
// 
// 【本产品为著作权产品，合法授权后请放心使用，禁止外传！】
// 【本次授权给：<北京小羊驼科技有限公司>，授权编号：<NT231212144350>，代码指纹：<A.702363430.550>，技术对接人微信：<ID: wxid_wbyootvkdcgj22>】
// 【授权寄送：<收件：苏先生、地址：北京市大兴区北京密码西区6号楼1单元301、电话：18613885610、邮箱：bd@huiyuanxiang-inc.com>】
// 
// 【本系列产品在国家版权局的著作权登记信息如下】：
// 1）国家版权局登记名(简称)和权证号：RainbowChat    （证书号：软著登字第1220494号、登记号：2016SR041877）
// 2）国家版权局登记名(简称)和权证号：RainbowChat-Web（证书号：软著登字第3743440号、登记号：2019SR0322683）
// 3）国家版权局登记名(简称)和权证号：RainbowAV      （证书号：软著登字第2262004号、登记号：2017SR676720）
// 4）国家版权局登记名(简称)和权证号：MobileIMSDK-Web（证书号：软著登字第2262073号、登记号：2017SR676789）
// 5）国家版权局登记名(简称)和权证号：MobileIMSDK    （证书号：软著登字第1220581号、登记号：2016SR041964）
// * 著作权所有人：江顺/苏州网际时代信息科技有限公司
// 
// 【违法或违规使用投诉和举报方式】：
// 联系邮件：jack.jiang@52im.net
// 联系微信：hellojackjiang
// 联系QQ号：413980957
// 授权说明：http://www.52im.net/thread-1115-1-1.html
// 官方社区：http://www.52im.net
package com.x52im.rbchat.logic.sns_group;

import android.app.Activity;
import android.content.Intent;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.eva.android.widget.ARecyclerViewAdapter;
//import com.eva.android.widget.AsyncBitmapLoader;
import com.eva.android.widget.DataLoadableFragment;
import com.x52im.rbchat.Const;
import com.x52im.rbchat.MyApplication;
import com.x52im.rbchat.R;
import com.x52im.rbchat.cache.ImageCacheLoader;
import com.x52im.rainbowchat.http.logic.dto.GroupEntity;
import com.x52im.rbchat.cache.GroupsProvider;
import com.x52im.rbchat.logic.sns_group.viewmodel.GroupsViewModel;
import com.x52im.rbchat.utils.ActivityRequestCode;
import com.x52im.rbchat.utils.IntentFactory;
import com.x52im.rbchat.utils.PreferencesToolkits;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

/**
 * 群聊列表Fragment实现类。
 *
 * @author JackJiang
 * @since 8.0
 */
public class GroupsFragment extends DataLoadableFragment {

    private final static String TAG = GroupsFragment.class.getSimpleName();

    /** 父布局 - 添加好友的父组件引用(当群列表为空时显示本布局) */
    private ViewGroup addGroupLL = null;

    /** 群列表 */
    private RecyclerView groupListView;
    /** 群列表Adapter */
    private GroupsListAdapter groupListAdapter;
    /** 群列表布局管理器 */
    private LinearLayoutManager layoutManager = null;
    /** 群列表数据ViewModel对象 */
    private GroupsViewModel viewModel4Groups;

    // [注意1]：Fragment中的onResume方法，在很多时候并不像Activity那样能被即时调用（比如当多个Fragment放置于
    //         ViewPager中时，子fragment的左右切换是不会触发Fragment的onResume方法，此时就需要与 setUserVisibleHint
    //         方法进行配合才能保证兜底（理论上，Fragment中的setUserVisibleHint和onResume方法，在Fragment
    //         可见性改变时总有一个会被调用），这样就能确保像Activity中那样不错过任何一次可性的触发
    // [注意2]：setUserVisibleHint方法中切不可调用涉及ui的代码，所有有关ui的代码都都应放在onCreateView内或之后调用，
    //         否则可能因Fragment在Activity中的生命周期问题，导致fragment中getActivity()或getContext()为null，
    //         但很适合在这样的方法中借助ViewModel+LiveData进行数据的加载和刷新（因其能自动处理Fragment和Activity
    //         的生命周期问题，因而这样用非常安全可靠）
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (groupListAdapter != null && isVisibleToUser) {
            Log.i(TAG, "@@@@2 AA-setUserVisibleHint已被调用，马上开始 loadGroupsData... "+System.currentTimeMillis());
            this.viewModel4Groups.loadGroupsData();
        }
    }

    @Override
    public void onCreateAfter() {
        // 拿到本类对应的ViewModel对象，实现MVVM架构
        viewModel4Groups = new ViewModelProvider(getActivity()).get(GroupsViewModel.class);
    }

    // 注意：Fragment中的onResume方法，在很多时候并不像Activity那样能被即时调用（比如当多个Fragment放置于
    // ViewPager中时，子fragment的左右切换是不会触发Fragment的onResume方法，此时就需要与 setUserVisibleHint
    // 方法进行配合才能保证兜底（理论上，Fragment中的setUserVisibleHint和onResume方法，在Fragment可见性改变时
    // 总有一个会被调用），这样就能确保像Activity中那样不错过任何一次可性的触发
    public void onResume() {
        super.onResume();
        Log.i(TAG, "@@@@2 AA-onResume已被调用，马上开始 loadGroupsData... "+System.currentTimeMillis());
        this.viewModel4Groups.loadGroupsData();
//        // 强制要求每次进来都更新列表（从而保证当数据更新后能确保不错过刷新最新的群员数、群名称等显示）
//        notifyVisibleDataSetChanged(layoutManager, groupListAdapter);
//        groupListAdapter.notifyDataSetChanged();
    }

    @Override
    protected int contentLayout() {
        return R.layout.groupchat_groups_fragment;
    }

    @Override
    protected View initViews(@NonNull LayoutInflater inflater, @Nullable ViewGroup container){
        View view = super.initViews(inflater, container);

        //* 各UI组件
        addGroupLL = view.findViewById(R.id.groupchat_groups_list_view_addGroupLL);
        //* 对列表对象进行相关初始化
        this.initRecyclerView(view);
        //* 初始化数据
        initDatas();

        return view;
    }

    /**
     * 本方法由父类的onCreate()调用，子类可在此方法中为各UI功能组件增加事件临听。
     */
    @Override
    protected void initListeners() {
        // “创建群聊”按钮事件处理
        addGroupLL.setOnClickListener(v -> gotoCreateGroup(getActivity(), null));
    }

    private void initRecyclerView(View view) {
        //列表
        groupListView = view.findViewById(R.id.groupchat_groups_list_listView);
        // 使RecyclerView保持固定的大小,这样会提高RecyclerView的性能
        groupListView.setHasFixedSize(true);

        //设置分割线（使用官方的一个默认实现，不然自已来画就太烦了）
        DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(c(), DividerItemDecoration.VERTICAL);
        dividerItemDecoration.setDrawable(ContextCompat.getDrawable(c(), R.drawable.groupchat_groups_listview_divider));
        groupListView.addItemDecoration(dividerItemDecoration);

        // 设置线性布局管理器
        groupListView.setLayoutManager(layoutManager = new LinearLayoutManager(c()));

        // 实例化Adapter
        groupListAdapter = new GroupsListAdapter(a(), position -> {
            GroupEntity contentData = groupListAdapter.getListData().get(position);
            if(contentData != null) {
                // 进入群聊天界面
                startActivity(IntentFactory.createGroupChatIntent(getActivity(), contentData.getG_id(), contentData.getG_name()));
            }
        });

        // 设置Adapter
        groupListView.setAdapter(groupListAdapter);
//        // 强制刷新显示（目的是触发内容改变并通知观察者）
//        groupListAdapter.notifyDataSetChanged();
    }

    private void initDatas(){
        // 数据模型LiveData绑定
        this.viewModel4Groups.getGroupsLiveData().observe(this, groupEntities -> {
            // 数据为空，表示数据模型只是更新（并非首次加载，只需要下方的notifyDataSetChanged()就可以）
            if(groupEntities != null) {
                // 为列表设置数据并显示最新数据（注意：此方法post给ui层的对象是全局群列表数据模型的浅拷贝，后续
                // 数据模型的数据改动，经LiveData的通知，只需要让ui层RecycleView即时调用notifyDataSetChanged()
                // 就能刷新最新数据显示，而不需要重复传递整个群列表数据了。）
                groupListAdapter.setListData(groupEntities);
            }
            // 刷新列表ui显示（确保数据模型的变动刷新在ui上）
//            notifyVisibleDataSetChanged(layoutManager, groupListAdapter);
            groupListAdapter.notifyDataSetChanged();
            // 显示内容ui
            showContent();

            Log.i(TAG, "@@@@2【GroupsFragment】收到reload完成的postValue！");
        });

//        // 首次载入列表数据（数据对象是IMClientManager中全局数据模型的浅拷贝）
//        this.viewModel4Groups.loadGroupsData();
    }

    /**
     * 进入建群页面。
     */
    public static void gotoCreateGroup(Activity activity, String defaultSelectedUid){
        Intent i = IntentFactory.createGroupMemberActivityIntent(activity, GroupMemberActivity.USED_FOR_CREATE_GROUP, null, true, defaultSelectedUid);
        // 建群完成后，需要处理 GroupMemberAcvitity界面的通知哦（即在本类的onActivityResult(..)方法中处理的）
        activity.startActivityForResult(i, ActivityRequestCode.REQUEST_CODE_FOR_CREATE_GROUP);
    }

    /**
     * 处理下一级Activity的结果回调通知.
     */
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        // 这是进入"创建群"的请求码（到此，意味着从建群界面返回了）
        if (requestCode == ActivityRequestCode.REQUEST_CODE_FOR_CREATE_GROUP) {// 将建群成功后的新建信息刷新到界面上及时显示
            if (resultCode == Activity.RESULT_OK) {
                // 刷新列表
//                groupListAdapter.notifyDataSetChanged();
                notifyVisibleDataSetChanged(layoutManager, groupListAdapter);
            }
        } else {// do nothing
            Log.d(TAG, "!!! onActivityResult-> requestCode=" + requestCode);
        }
    }

    /**
     * 获得下载指定群头像的完整http地址.
     * <p>
     * 形如：“http://192.168.88.138:8080/BinaryDownloader?
     * action=gavartar_d&user_uid=400007&file_name=0000000152.jpg”。
     *
     * @param gid 要下载群头像的群id
     * @return 完整的http文件下载地址
     */
    public static String getGroupAvatarDownloadURL(String gid)
    {
        String fileURL = null;
        if(MyApplication.getInstance2().getIMClientManager().getLocalUserInfo() != null)
            fileURL = Const.BBONERAY_DOWNLOAD_CONTROLLER_URL_ROOT
                    +"?action=gavartar_d"
                    // 要下载图片的用户uid
                    +"&user_uid="+MyApplication.getInstance2().getIMClientManager().getLocalUserInfo().getUser_uid()
                    +"&file_name="+gid+".jpg";
        return fileURL;
    }

    //-------------------------------------------------------------------------------- 内部类

    /**
     * 群列表的adapter类实现.
     */
    private class GroupsListAdapter extends ARecyclerViewAdapter<GroupEntity>{

        public GroupsListAdapter(Activity context, ARecyclerViewAdapter.OnItemClickListener onItemClickListener) {
            super(context, R.layout.groupchat_groups_fragment_list_item, onItemClickListener);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            return new LinearViewHolder(layoutInflater.inflate(itemResId, parent,false));
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, final int position) {
            // 别忘了调用父类方法
            super.onBindViewHolder(viewHolder, position);

            // 正在操作的viewHolder对象
            LinearViewHolder holder = (LinearViewHolder)viewHolder;
            // 正在操作的列表行的数据集
            final GroupEntity rowData = listData.get(position);

            //----------------------------------------------------------------------------- （1）
            //给标签设置值，以供用户查看
            holder.viewGroupName.setText(rowData.getG_name());
            holder.viewMemberCount.setText("("+rowData.getG_member_count()+"人)");
            holder.viewOwnerIcon.setVisibility(GroupsProvider.isGroupOwner(rowData.getG_owner_user_uid())?View.VISIBLE:View.INVISIBLE);
            holder.viewCreateTime.setText("创建于："+rowData.getCreate_time());
            // 消息提示是否静音的图标显示
            // TODO: 有优化余地——直接从Preferences里读有可能会在大量列表数据的情况下受Android的Preferences性能影响哦
            if(PreferencesToolkits.isChatMsgToneOpen(getActivity(), rowData.getG_id()))
                holder.viewSilentIcon.setVisibility(View.GONE);
            else
                holder.viewSilentIcon.setVisibility(View.VISIBLE);

            //----------------------------------------------------------------------------- （2）异步加载群头像
            // 以下代码，解决Glide在RecycleView中图片错位或重复显示问题
            Glide.with(context).clear(holder.viewGroupIcon);// 解决方法2
            // 强行先设置默认群头像（确保list重用的view在网络异步情况下未加完成时能清除掉listview里之前设置的图片）
            holder.viewGroupIcon.setImageResource(R.drawable.groupchat_groups_icon_default);

            if(rowData.getG_id() != null) {
                // 加载群头像
                ImageCacheLoader.loadGroupImgWithGlide(Glide.with(getContext()), rowData.getG_id(), holder.viewGroupIcon, 7 , false, -1);// 圆角单位是dp，（相当于xxhdpi下的21像素）
            }
        }

        /**
         * 根据RecyclerView内容的变动，来决定无数据时的UI内容显示。
         */
        @Override
        protected void dataSetChanged(){
            // 当存在群时就隐藏掉创建群的组件（当一个群也不存在时就显示，目的是引导用户创建群，仅此而已）
            boolean hasItems = (this.getListData().size() > 0);
            addGroupLL.setVisibility(hasItems ? View.GONE : View.VISIBLE);
            groupListView.setVisibility(hasItems ? View.VISIBLE : View.GONE);
        }
    }

    /**
     * ViewHolder实现类。
     */
    private class LinearViewHolder extends RecyclerView.ViewHolder{

        ViewGroup layoutOfGotochat = null;
        TextView viewGroupName = null;
        TextView viewCreateTime = null;
        TextView viewMemberCount = null;
        ImageView viewGroupIcon = null;
        ImageView viewOwnerIcon = null;
        ImageView viewSilentIcon = null;

        public LinearViewHolder(View itemView) {
            super(itemView);

            // item里的操作组件实例
            layoutOfGotochat = itemView.findViewById(R.id.groupchat_groups_list_item_contentLL);
            viewGroupName = itemView.findViewById(R.id.groupchat_groups_list_item_nameView);
            viewMemberCount = itemView.findViewById(R.id.groupchat_groups_list_item_membernumView);
            viewGroupIcon = itemView.findViewById(R.id.groupchat_groups_list_item_imageView);
            viewOwnerIcon = itemView.findViewById(R.id.groupchat_groups_list_item_ownerView);
            viewCreateTime = itemView.findViewById(R.id.groupchat_groups_list_item_createTimeView);
            viewSilentIcon = itemView.findViewById(R.id.groupchat_groups_list_item_silentIconView);
        }
    }
}
